package simple_sql

import (
	"database/sql"
	"fmt"
	"strings"
)

// QueryDel 是用于构建和执行 DELETE SQL 查询的结构体。
type QueryDel struct {
	query     *sql.DB
	tx        *sql.Tx
	tableName string
	where     strings.Builder
	whereArgs []any
	err       error
}

// Where 添加 WHERE 子句到 SQL 查询。
// 参数 opList 是一个 Operator 列表，用于构建 WHERE 子句的过滤条件。
func (q *QueryDel) Where(opList ...Operator) *QueryDel {
	// 如果查询条件有错误或过滤条件为空，则直接返回。
	if q.err != nil || opList == nil || len(opList) == 0 {
		return q
	}

	// 创建一个字符串构建器，用于构造过滤条件。
	var filter strings.Builder
	// 构造过滤条件并添加到where部分。
	for _, op := range opList {
		operator, value, err := op.toSql()
		if err != nil {
			q.err = err
			return q
		}
		if filter.Len() != 0 {
			filter.WriteString(" AND")
		}
		filter.WriteString(operator)
		q.whereArgs = append(q.whereArgs, value...)
	}
	// 判断是否首次的过滤条件，不是添加（AND、OR）
	q.where.WriteString(fmt.Sprintf("(%s )", filter.String()))

	// 返回Query指针，支持链式调用。
	return q
}

// And 在 WHERE 子句中添加 AND 条件。
// 参数 opList 是一个 Operator 列表，用于构建 AND 子句的过滤条件。
func (q *QueryDel) And(opList ...Operator) *QueryDel {
	if q.err != nil || opList == nil || len(opList) == 0 {
		return q
	}

	q.where.WriteString(" AND")
	q.Where(opList...)

	return q
}

// Or 在 WHERE 子句中添加 OR 条件。
// 参数 opList 是一个 Operator 列表，用于构建 OR 子句的过滤条件。
func (q *QueryDel) Or(opList ...Operator) *QueryDel {
	if q.err != nil || opList == nil || len(opList) == 0 {
		return q
	}

	q.where.WriteString(" OR")
	q.Where(opList...)

	return q
}

// Exec 执行构建好的 DELETE SQL 查询，并返回受影响的行数。
func (q *QueryDel) Exec() (int64, error) {
	// 检查是否存在预设错误
	if q.err != nil {
		return 0, q.err
	}
	// 确保where条件不为空
	if q.where.Len() == 0 {
		return 0, fmt.Errorf("where条件不能为空")
	}
	// 构造完整的DELETE SQL语句
	query := "DELETE FROM " + q.tableName + " WHERE " + q.where.String()

	// 初始化错误变量和结果变量
	var err error
	var result sql.Result
	// 根据是否存在事务来执行SQL语句
	if q.tx != nil {
		result, err = q.tx.Exec(query, q.whereArgs...)
	} else {
		result, err = q.query.Exec(query, q.whereArgs...)
	}
	// 检查执行过程中是否发生错误
	if err != nil {
		return 0, err
	}
	// 返回受影响的行数
	return result.RowsAffected()
}
